<html>
 <head>
  <meta charset="UTF-8">
 </head>
 <body>
  <h1 data-lake-id="HCMU8" id="HCMU8"><span data-lake-id="u2010189b" id="u2010189b">典型回答</span></h1>
  <p data-lake-id="u87b87fc5" id="u87b87fc5"><br></p>
  <p data-lake-id="u6c4ead47" id="u6c4ead47"><span data-lake-id="u8ae16a0d" id="u8ae16a0d">Redis Stream 是 Redis 5.0 版本新增加的数据结构，主要用于处理有序的、可追溯的消息流。</span></p>
  <p data-lake-id="u3e20d8b0" id="u3e20d8b0"><span data-lake-id="u401f1a8a" id="u401f1a8a">​</span><br></p>
  <p data-lake-id="u8d50b515" id="u8d50b515"><span data-lake-id="ucc2a8abc" id="ucc2a8abc">Stream数据结构可以被视为一个日志或消息队列，其中每个消息都有一个唯一的ID，并且按照添加的顺序进行排序。开发人员可以向Stream中添加消息、读取消息、删除消息以及订阅消息。Stream数据结构还支持消费者组，可以让多个消费者并发地处理消息流。</span></p>
  <p data-lake-id="u26de51de" id="u26de51de"><span data-lake-id="ue5e4a645" id="ue5e4a645">​</span><br></p>
  <p data-lake-id="ud26128f5" id="ud26128f5"><span data-lake-id="u0c861a70" id="u0c861a70">在Redis 5.0之前，通过Redis的发布订阅 (pub/sub) 可以实现消息队列的功能，但它有个缺点就是消息无法持久化，如果出现网络断开、Redis 宕机等，消息就会被丢弃。</span></p>
  <p data-lake-id="uea86d6aa" id="uea86d6aa"><span data-lake-id="u3fa9a15d" id="u3fa9a15d">​</span><br></p>
  <p data-lake-id="u5a888a36" id="u5a888a36"><span data-lake-id="u0856cc7f" id="u0856cc7f">而 Redis Stream 提供了消息的持久化和主备复制功能，可以让任何客户端访问任何时刻的数据，并且能记住每一个客户端的访问位置，还能保证消息不丢失。</span></p>
  <p data-lake-id="ubdc69511" id="ubdc69511"><span data-lake-id="u95b3e3ae" id="u95b3e3ae">​</span><br></p>
  <p data-lake-id="u8cc365d0" id="u8cc365d0"><span data-lake-id="u37565967" id="u37565967">他的特点是支持持久化、消息具有有序性，并且支持分组。主要可以用来做消息队列、日志收集、实时数据处理和聊天室应用等。</span></p>
  <p data-lake-id="u1ababc00" id="u1ababc00"><br></p>
  <p data-lake-id="u3bf92464" id="u3bf92464"><strong><span data-lake-id="ud9f27d23" id="ud9f27d23">有序性</span></strong><span data-lake-id="u221785ae" id="u221785ae">：消息可以按照发布时间排序，消费者可以按照消息发布的时间顺序进行消费。</span></p>
  <p data-lake-id="u32674889" id="u32674889"><strong><span data-lake-id="u63058c96" id="u63058c96">多消费者支持</span></strong><span data-lake-id="u5863a903" id="u5863a903">：多个消费者可以订阅同一个Stream并独立消费消息，支持竞争式消费和共享式消费两种消费模式。</span></p>
  <p data-lake-id="u256201c4" id="u256201c4"><strong><span data-lake-id="u9025ecc4" id="u9025ecc4">持久化</span></strong><span data-lake-id="ue0198291" id="ue0198291">：Stream支持消息持久化，即使Redis服务器重启或崩溃，之前的消息仍然可以恢复。</span></p>
  <p data-lake-id="ubb62be14" id="ubb62be14"><strong><span data-lake-id="u54565894" id="u54565894">消息分组</span></strong><span data-lake-id="u9c585168" id="u9c585168">：Stream支持消息分组功能，可以将消息分配到不同的消费组中，从而实现更灵活的消息消费。</span></p>
  <p data-lake-id="u525131f7" id="u525131f7"><br></p>
  <h1 data-lake-id="dMAw8" id="dMAw8"><span data-lake-id="u74e38abe" id="u74e38abe">扩展知识</span></h1>
  <p data-lake-id="ue62be3f0" id="ue62be3f0"><br></p>
  <h2 data-lake-id="Hxgbg" id="Hxgbg"><span data-lake-id="u726f1651" id="u726f1651">实现原理</span></h2>
  <p data-lake-id="u27afb085" id="u27afb085"><br></p>
  <p data-lake-id="u55a64d94" id="u55a64d94"><span data-lake-id="ub31e48f3" id="ub31e48f3">Stream底层采用了类似于日志的</span><strong><span data-lake-id="ube2b3df8" id="ube2b3df8">数据结构</span></strong><span data-lake-id="ue4b34cac" id="ue4b34cac">，每个Stream都是由一个或多个日志实现的。每个日志包含多个消息，</span><strong><span data-lake-id="u3674c729" id="u3674c729">每个消息包含一个唯一的ID和一些附加的字段，如消息体、时间戳等。</span></strong></p>
  <p data-lake-id="u91797769" id="u91797769"><strong><span data-lake-id="u81eeff41" id="u81eeff41">​</span></strong><br></p>
  <p data-lake-id="u78371116" id="u78371116"><span data-lake-id="u26106a50" id="u26106a50">Redis提供了一系列的Stream命令，用于创建Stream、发布/消费消息。</span></p>
  <p data-lake-id="u5d001dba" id="u5d001dba"><span data-lake-id="ubf2816e1" id="ubf2816e1">​</span><br></p>
  <p data-lake-id="ue9d384e0" id="ue9d384e0" style="text-align: center"><img src="https://cdn.nlark.com/yuque/0/2023/png/5378072/1677999737585-29851bb1-8e2b-4d32-8ab9-10ce2b456b25.png?x-oss-process=image%2Fwatermark%2Ctype_d3F5LW1pY3JvaGVp%2Csize_17%2Ctext_SmF2YSA4IEd1IFA%3D%2Ccolor_FFFFFF%2Cshadow_50%2Ct_80%2Cg_se%2Cx_10%2Cy_10"></p>
  <p data-lake-id="ubb25300f" id="ubb25300f"><br></p>
  <p data-lake-id="uf9f6fcdb" id="uf9f6fcdb"><br></p>
  <p data-lake-id="u9ea25ef5" id="u9ea25ef5"><span data-lake-id="u8b9a7f50" id="u8b9a7f50">当一个消息被发布到Stream中时，它将被写入Stream日志中，每个消息都有一个唯一的ID和一些可选的字段，如时间戳、消息体等。消息ID是自动分配的，可以使用自然数或UUID作为ID。</span></p>
  <p data-lake-id="u6d79bf22" id="u6d79bf22"><br></p>
  <p data-lake-id="udb907658" id="udb907658"><span data-lake-id="uf30fe152" id="uf30fe152">当一个消费者订阅了一个Stream并开始消费消息时，它可以使用XREAD命令从Stream中读取消息。消费者可以使用XGROUP命令将自己加入到一个消费组中，并使用XREADGROUP命令从该组中读取消息。消费者可以使用XACK命令来确认已经消费的消息，避免消息被重复消费。</span></p>
  <p data-lake-id="u838a8c47" id="u838a8c47"><span data-lake-id="u779a38ad" id="u779a38ad">​</span><br></p>
  <p data-lake-id="u76bb8310" id="u76bb8310"><span data-lake-id="ucfbe7d76" id="ucfbe7d76">他还支持消息分组的功能，当一个消费组被创建时，它将与一个Stream相关联，并包含一个消费组名称和一个偏移量。消费组可以有多个消费者，消费者可以独立地从Stream中读取消息。当一个消费者开始消费消息时，它将记录当前的消费偏移量，并在处理完所有消息后将其更新到消费组中。消费组可以使用XPENDING命令查找未确认的消息，从而处理消息的超时和未确认情况。</span></p>
 </body>
</html>